unit Controller;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, Forms, Controls, DataRecord, MainFr;

type

  { TController }

  /// Classe para controle de frames
  TController = class
  private
    /// Conteiner para exibição dos frames
    FParentControl: TWinControl;
    /// Vetor com os frames a serem exibidos
    FFrameList: array of TMainFrame;
    /// Acrescenta um frame a lista de frames
    /// @param(Frame é o frame a ser acrescentado na lista)
    procedure AddFrame(Frame: TMainFrame);
    /// Exibe o último frame do vetor
    procedure Show();
    /// Fecha todos os frames
    procedure CloseAllFrames();
  public
    /// Construtor
    /// @param (ParentControl é o conteiner onde os frames serão exibidos)
    constructor Create(ParenteControl: TWinControl);
    /// Exibe um frame sem retorno de dados e com limpeza de dataset
    /// @param (Frame é o frame a ser exibido)
    procedure ShowFrame(Frame: TMainFrame);
    /// Exibe um frame sem retorno de dados e sem limpeza de dataset
    /// @param (Frame é o frame a ser exibido)
    procedure ShowSearchFrame(Frame: TMainFrame);
    /// Exibe um frame com retorno de dados e com limpeza de dataset
    /// @param (Frame é o frame a ser exibido)
    procedure ShowForeignFrame(Frame: TMainFrame);
    /// Volta para o frame anterior ao atual
    procedure BackFrame();
  end;

implementation

uses MainRecordFr;

{ TController }

procedure TController.AddFrame(Frame: TMainFrame);
begin
  // Aumenta o tamanho do vetor
  SetLength(FFrameList, Length(FFrameList) + 1);
  // Acrescenta o frame a lista
  FFrameList[Length(FFrameList) - 1] := Frame;
end;

procedure TController.Show();
var
  Frame: TMainFrame;
begin
  // Se for diferente do frame atual
  if (Length(FFrameList) > 0) then begin
    // pega o último frame do vetor
    Frame := FFrameList[Length(FFrameList) - 1];
    // Exibe o frame
    Frame.Parent := FParentControl;
    Frame.Align := alClient;
    // Se o frame for um TMainRecordFrame
    if Frame is TMainRecordFrame then
      // Chame o controle de botões
      TMainRecordFrame(Frame).ControlaBotoes();
    // Muda o caption do conteiner
    FParentControl.Caption :=
      FFrameList[Length(FFrameList) - 1].Caption + ' - ' + Application.Title;
  end else begin
    FParentControl.Caption := Application.Title;
  end;
end;

procedure TController.CloseAllFrames();
var
  Frame: TMainFrame;
begin
  // Enquando houverem frames abertos
  while (Length(FFrameList) > 0) do begin
    // Pega o último frame
    Frame := FFrameList[Length(FFrameList) - 1];
    // Remove o frame do conteiner
    Frame.Close();
    // Remove o frame do vetor
    SetLength(FFrameList, Length(FFrameList) - 1);
  end;
end;

constructor TController.Create(ParenteControl: TWinControl);
begin
  FParentControl := ParenteControl;
end;

procedure TController.ShowFrame(Frame: TMainFrame);
begin
  if (Frame <> nil) then begin
    // Fecha todos os frames abertos
    CloseAllFrames();
    // Indica limpeza do dataset
    Frame.CloseData := True;
    // Indica não retorno de dados
    Frame.ReturnData := False;
    // Abre o Data set do frame
    Frame.Open();
    // Adiciona o frame ao vetor
    AddFrame(Frame);
    // Exibe o frame
    Show();
  end;
end;

procedure TController.ShowSearchFrame(Frame: TMainFrame);
begin
  if (Frame <> nil) then begin
    // Indica não limpeza do dataset
    Frame.CloseData := False;
    // Indica não retorno de dados
    Frame.ReturnData := False;
    // Adiciona o frame ao vetor
    AddFrame(Frame);
    // Exibe o frame
    Show();
  end;
end;

procedure TController.ShowForeignFrame(Frame: TMainFrame);
begin
  if (Frame <> nil) then begin
    // Indica não limpeza do dataset
    Frame.CloseData := True;
    // Indica não retorno de dados
    Frame.ReturnData := True;
    // Adiciona o frame ao vetor
    AddFrame(Frame);
    // Exibe o frame
    Show();
  end;
end;

procedure TController.BackFrame();
var
  Data: TDataRecord;
  CurrentFrame: TMainFrame;
  ReturnData: boolean;
begin
  // Verifica se existe pelo menos dois frames
  if (Length(FFrameList) > 1) then begin
    // Verifica se deve haver a limpeza de dataset para o frame atual
    CurrentFrame := FFrameList[Length(FFrameList) - 1];
    // Verifica se deve haver retorno de dados
    ReturnData := CurrentFrame.ReturnData;
    if (ReturnData) then begin
      // Obtém os dados do frame atual
      Data := CurrentFrame.GetDataRecord();
    end;
    // Fecha o frame
    CurrentFrame.Close();
    SetLength(FFrameList, Length(FFrameList) - 1);
    // Agora temos um novo frame atual
    CurrentFrame := FFrameList[Length(FFrameList) - 1];
    if (ReturnData) then begin
      // Atribui os dados ao frame atual
      CurrentFrame.SetDataRecord(Data);
    end;
  end else begin
    CloseAllFrames();
  end;
  // Exibe o frame
  Show();
end;

end.
